#pragma once
#include <sys/types.h>
#include <sys/socket.h>
#include <iostream>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include "Log.hpp"

#define CONV(name) ((struct sockaddr *)(name))
#define BACKLOG 8
#define DIE(num) (exit(num))

enum EXITCODE
{
    SOCKET_ERROR,
    BIND_ERROR,
    LISTEN_ERROR,
    READ_ERROR
};

const int gdefaultPort = 8080;
using namespace LogModule;

class TcpServer
{
public:
    TcpServer(uint16_t port = gdefaultPort) : _port(port),
                                              _isrunning(false),
                                              _listensockfd(-1)
    {
    }

    void InitServer()
    {
        // 创建 bind 监听
        //  1. 创建socket
        _listensockfd = socket(AF_INET, SOCK_STREAM, 0);
        if (_listensockfd < 0)
        {
            perror("socket error");
            DIE(SOCKET_ERROR);
        }

        struct sockaddr_in inet;
        inet.sin_family = AF_INET;
        inet.sin_addr.s_addr = INADDR_ANY;
        inet.sin_port = ::htons(_port);

        // 2.加载进入内核
        int n = bind(_listensockfd, CONV(&inet), sizeof(inet));
        if (n == -1)
        {
            perror("bind error");
            DIE(BIND_ERROR);
        }
        std::cout << "bind success port:" << _port << std::endl;

        // 3.监听
        n = ::listen(_listensockfd, BACKLOG);
        if (n < 0)
        {
            DIE(LISTEN_ERROR);
        }
        std::cout << "listen success, sockfd is : " << _port << std::endl;
    }

    void Handle(int sockfd)
    {
        while (true)
        {
            char buffer[1024];

            int n = ::read(sockfd, buffer, sizeof(buffer) - 1);
            
            if (n == 0)
            {
                break; // 读取结尾
            }
            else if (n == -1)
            {
                DIE(READ_ERROR);
            }
            buffer[n] = 0;
            std::cout << buffer << std::endl;

            std::string info = "echo#";
            info += buffer;
            ::write(sockfd, info.c_str(), info.size());
        }

        ::close(sockfd);
    }
    void Start()
    {
        _isrunning = true;

        while (true)
        {
            struct sockaddr_in peer;
            socklen_t peer_len = sizeof(peer);
            int sockfd = ::accept(_listensockfd, CONV(&peer), &peer_len);
            if (sockfd == -1)
            {
                LOG(LogLevel::ERROR) << "连接错误";
            }

            char ipbuffer[64];
            const char *ip = ::inet_ntop(AF_INET, &peer.sin_addr, ipbuffer, sizeof(ipbuffer));

            LOG(LogLevel::INFOMATION) << "连接成功,IP:" << ipbuffer << "fd:" << sockfd;
            Handle(sockfd);
        }
    }

private:
    int _listensockfd;
    uint16_t _port;
    bool _isrunning;
};